package com.bong.panpan.bongcharttools;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.RectF;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.ArrayMap;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;

import com.bong.panpan.bongcharttools.custom.Constant;
import com.bong.panpan.bongcharttools.custom.HeartRateRecord;
import com.bong.panpan.bongcharttools.custom.MyMarkerView;
import com.bong.panpan.bongcharttools.custom.SpUtil;
import com.bong.panpan.bongcharttools.util.Common;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.MPPointD;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by panpan on 2017/9/26.
 */

public class TempShowHelper implements OnChartGestureListener, OnChartValueSelectedListener {

    LineChart mChart;
    Button beginBtn;
    Button clearBtn;
    Button saveBtn;
    Button loadBtn;
    CheckBox valueCheck;
    CheckBox circleCheck;
    Spinner modeSpinner;
    View menuLayout;
    Button menuBtn;
    Activity activity;
    private ArrayMap<String, float[]> legendNames = new ArrayMap<>();
    private ArrayMap<String, Boolean> legendUpdated = new ArrayMap<>();
    private int presentX = 0;
    private Runnable uiThreadRun;//ui线程运行时调用
    private float contentCenterY = 0;
   //private final Semaphore semaphore = new Semaphore(0);

    public TempShowHelper(LineChart mChart,
                          Button beginBtn,
                          Button saveBtn,
                          Button clearBtn,
                          Button loadBtn,
                          CheckBox valueCheck,
                          CheckBox circleCheck,
                          Spinner modeSpinner,
                          View menuLayout,
                          Button menuBtn,
                          Activity activity) {
        this.mChart = mChart;
        this.beginBtn = beginBtn;
        this.saveBtn = saveBtn;
        this.clearBtn = clearBtn;
        this.loadBtn = loadBtn;
        this.valueCheck = valueCheck;
        this.circleCheck = circleCheck;
        this.modeSpinner = modeSpinner;
        this.menuLayout = menuLayout;
        this.menuBtn = menuBtn;
        this.activity = activity;
        chartInit();
        valueCheck.setOnCheckedChangeListener(checkedChangeListener);
        circleCheck.setOnCheckedChangeListener(checkedChangeListener);
        modeSpinner.setOnItemSelectedListener(spinnerListener);
        int position = SpUtil.getInstance().getInt("TempShowHelper:modeSpinner", 2);
        this.modeSpinner.setSelection(position);
        boolean checked = SpUtil.getInstance().getBoolean("TempShowHelper:valueCheck", true);
        this.valueCheck.setChecked(checked);
        checked = SpUtil.getInstance().getBoolean("TempShowHelper:circleCheck", true);
        this.circleCheck.setChecked(checked);

    }

    private void chartInit() {
        mChart.setOnChartGestureListener(this);
        mChart.setOnChartValueSelectedListener(this);
        mChart.setDrawGridBackground(false);

        // no description text
        //mChart.getDescription().setEnabled(false);
        Description desc = new Description();
        desc.setText("Temperature");
        mChart.setDescription(desc);

        // enable touch gestures
        mChart.setTouchEnabled(true);

        // enable scaling and dragging
        mChart.setDragEnabled(true);
        mChart.setScaleEnabled(true);
        mChart.setScaleXEnabled(true);
        mChart.setScaleYEnabled(true);

        // if disabled, scaling can be done on x- and y-axis separately
        mChart.setPinchZoom(false);
        // set an alternative background color
        // mChart.setBackgroundColor(Color.GRAY);

        // create a custom MarkerView (extend MarkerView) and specify the layout
        // to use for it
        MyMarkerView mv = new MyMarkerView(activity, R.layout.custom_marker_view);
        mv.setChartView(mChart); // For bounds control
        mChart.setMarker(mv); // Set the marker to the chart

        YAxis leftAxis = mChart.getAxisLeft();
        leftAxis.setAxisMinimum(10f+5);
        leftAxis.setAxisMaximum(50f+5);
        leftAxis.enableGridDashedLine(10f, 10f, 0f);
        leftAxis.setDrawZeroLine(false);

        YAxis rightAxis = mChart.getAxisRight();
        rightAxis.setAxisMinimum(0f-15);
        rightAxis.setAxisMaximum(40f-15);
        rightAxis.enableGridDashedLine(10f, 10f, 0f);
        rightAxis.setDrawZeroLine(false);

        //mChart.getAxisRight().setEnabled(false);

        XAxis xAxis = mChart.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.enableGridDashedLine(10f, 10f, 0f);
        xAxis.setAxisMinimum(0);
        //xAxis.setAxisMaximum(100);
        xAxis.setAvoidFirstLastClipping(true);

        mChart.setVisibleXRangeMaximum(20);

        mChart.setHighlightPerDragEnabled(true);
        //mChart.setAutoScaleMinMaxEnabled(true);

        // add data
        //setData(30,6000, 100);
        //leftAxis.setAxisMinimum(6000f);
        //mChart.setVisibleXRangeMaximum(20);

        //mChart.setVisibleYRangeMaximum(25, YAxis.AxisDependency.LEFT);
        //mChart.moveViewTo(0,5000,YAxis.AxisDependency.LEFT);

        //mChart.setVisibleXRange(20);
//        mChart.setVisibleYRange(20f, AxisDependency.LEFT);
//        mChart.centerViewTo(20, 50, AxisDependency.LEFT);

        //mChart.animateX(2500);
        //mChart.animateXY(3000, 3000);
        //mChart.invalidate();

        // get the legend (only possible after setting data)
        Legend l = mChart.getLegend();

        // modify the legend ...
        l.setForm(Legend.LegendForm.LINE);

        // // dont forget to refresh the drawing
        // mChart.invalidate();
    }

    public synchronized void setChartData(String name, float... data) {
        this.legendNames.put(name, data);
        this.legendUpdated.put(name, true);
//        if (semaphore.availablePermits() == 0)
//            semaphore.release();
        activity.runOnUiThread(UIRunnable);
    }

    private int colorIndex = 0;
    private final int color[] = new int[]{0xFFFA6400, 0xFF0000FF, 0xFFFF00FF, 0xFF25A900, 0xFF000000, 0xFF948C01};

    private int getColor() {
        colorIndex++;
        colorIndex %= color.length;
        return color[colorIndex];
    }

    final String TempName = "_Temp";
    final String ACCName = "_ACC";

    private boolean addEntry() {
        LineData data = mChart.getData();
        LineDataSet set;
        if (data == null) {
            data = new LineData();
            mChart.setData(data);
        }
        if (legendNames.size() == 0) {
            return false;
        }
        if (data.getDataSetCount() != legendNames.size() * 2) {
            for (int i = 0; i < legendNames.size(); i++) {
                if (data.getDataSetByLabel(legendNames.keyAt(i) + TempName, false) != null)
                    continue;
                if (data.getDataSetByLabel(legendNames.keyAt(i) + ACCName, false) != null)
                    continue;
                set = createSet(legendNames.keyAt(i) + TempName, getColor());
                set.setMode(LineDataSet.Mode.values()[modeSpinner.getSelectedItemPosition()]);
                set.setDrawValues(valueCheck.isChecked());
                set.setDrawCircles(circleCheck.isChecked());
                data.addDataSet(set);
                set = createRightSet(legendNames.keyAt(i) + ACCName, getColor());
                set.setMode(LineDataSet.Mode.values()[modeSpinner.getSelectedItemPosition()]);
                set.setDrawValues(valueCheck.isChecked());
                set.setDrawCircles(circleCheck.isChecked());
                data.addDataSet(set);
            }
        }
        for (int i = 0; i < legendNames.size(); i++) {
            if (legendUpdated.get(legendNames.keyAt(i))) //判断是哪个更新
            {
                String name = legendNames.keyAt(i) + TempName;
                set = (LineDataSet) data.getDataSetByLabel(name, false);
                if (set != null)
                    set.addEntry(new Entry(presentX, legendNames.valueAt(i)[0]));
                name = legendNames.keyAt(i) + ACCName;
                set = (LineDataSet) data.getDataSetByLabel(name, false);
                if (set != null)
                    set.addEntry(new Entry(presentX, legendNames.valueAt(i)[1]));
                legendUpdated.put(legendNames.keyAt(i), false);
            }
        }
        data.notifyDataChanged();
        mChart.notifyDataSetChanged();
        mChart.setVisibleXRangeMaximum(30);
        //mChart.moveViewToX(data.getEntryCount());
        mChart.moveViewTo(data.getEntryCount(), contentCenterY, YAxis.AxisDependency.LEFT);
        return true;
    }

    private boolean isUIRun = false;
    private Runnable UIRunnable = new Runnable() {
        @Override
        public void run() {
            if (legendNames.size() != 0) {
                addEntry();
                presentX++;
            }
            isUIRun = false;
        }
    };

    /**
     * 加载特定的数据
     */
    public void loadChartData(String path) {
        onClearClicked();
        HeartRateRecord record = HeartRateRecord.load(path);
        LineData data2 = new LineData();
        mChart.setData(data2);
        LineDataSet set;
        int i = 0;
        for (Map.Entry<String, int[]> data :
                record.heartData.entrySet()) {
            String label = data.getKey();
            int[] values = data.getValue();
            set = createSet(label, getColor());
            set.setMode(LineDataSet.Mode.values()[modeSpinner.getSelectedItemPosition()]);
            set.setDrawValues(valueCheck.isChecked());
            set.setDrawCircles(circleCheck.isChecked());
            for (int j = 0; j < values.length; j += 2) {
                set.addEntry(new Entry(values[j], values[j + 1]));
            }
            data2.addDataSet(set);
        }
        data2.notifyDataChanged();
        mChart.notifyDataSetChanged();
        mChart.setVisibleXRangeMaximum(30);
        mChart.moveViewToX(data2.getEntryCount());
    }

    private void saveFile(String fileName) throws Exception {
        File file = new File(Constant.heartStorePath + "/" + fileName + Constant.heartEndName);
        if (file.exists() && file.isFile())
            throw new Exception("文件\"" + fileName + "\"已存在，请使用其他的文件名");
        //save file
        LineData data = mChart.getData();
        LineDataSet set;
        HeartRateRecord record = new HeartRateRecord();
        record.heartData = new HashMap<>();
        for (int i = 0; i < data.getDataSetCount(); i++) {
            set = (LineDataSet) data.getDataSetByIndex(i);
            List<Entry> entries = set.getValues();
            String label = set.getLabel();
            int[] values = new int[entries.size() * 2];
            for (int j = 0; j < entries.size(); j++) {
                values[j * 2] = (int) entries.get(j).getX();
                values[j * 2 + 1] = (int) entries.get(j).getY();
            }
            record.heartData.put(label, values);
        }
        HeartRateRecord.save(record, file.getPath());
    }

    public void beginClick(View v) {
        if ("开始".equals(beginBtn.getText().toString())) {
            //startChartThread();
            beginBtn.setText("停止");
        } else {
            //stopChartThread();
            beginBtn.setText("开始");
        }
    }

    private AlertDialog alertDialog;
    private EditText alertEdit;
    private TextWatcher alertEditListerner = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (!"".equals(s.toString())) {
                alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
            }
        }
    };

    public void saveClick(View v) {
        if (mChart.getData() == null) {
            Common.showToast(activity, "没有可以保存的数据");
            return;
        }
        if (alertDialog == null) {
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            builder.setTitle("提示");
            alertEdit = new EditText(activity);
            alertEdit.setHint("请输入文件名");
            alertEdit.addTextChangedListener(alertEditListerner);
            builder.setView(alertEdit);
            builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String fileName = alertEdit.getText().toString();
                    try {
                        saveFile(fileName);
                        Common.showToast(activity, "保存成功");
                        ((TempShowActivity) activity).getChartListFragment().refreshList();
                    } catch (Exception e) {
                        e.printStackTrace();
                        Common.showToast(activity, "保存失败\n" + e.getMessage());
                    }
                }
            });
            builder.setNegativeButton("取消", null);
            alertDialog = builder.create();
        }
        alertEdit.setText("");
        alertDialog.show();
        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
    }

    public void onClearClicked() {
        contentCenterY = 0;
        presentX = 0;
        legendNames.clear();
        mChart.clear();
        mChart.invalidate();
    }

    private CompoundButton.OnCheckedChangeListener checkedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            List<ILineDataSet> sets;
            switch (buttonView.getId()) {
                case R.id.value_check:
                    SpUtil.getInstance().setBoolean("TempShowHelper:valueCheck", isChecked);
                    if (mChart.getData() == null)
                        break;
                    sets = mChart.getData()
                            .getDataSets();
                    for (ILineDataSet iSet : sets) {
                        LineDataSet set = (LineDataSet) iSet;
                        set.setDrawValues(isChecked);
                    }
                    mChart.invalidate();
                    break;
                case R.id.circle_check:
                    SpUtil.getInstance().setBoolean("TempShowHelper:circleCheck", isChecked);
                    if (mChart.getData() == null)
                        break;
                    sets = mChart.getData()
                            .getDataSets();
                    for (ILineDataSet iSet : sets) {

                        LineDataSet set = (LineDataSet) iSet;
                        set.setDrawCircles(isChecked);
                    }
                    mChart.invalidate();
                    break;
                default:
                    break;
            }
        }
    };
    private AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            SpUtil.getInstance().setInt("TempShowHelper:modeSpinner", position);
            if (mChart.getData() == null)
                return;
            List<ILineDataSet> sets = mChart.getData().getDataSets();
            for (ILineDataSet iSet : sets) {
                LineDataSet set = (LineDataSet) iSet;
                set.setMode(LineDataSet.Mode.values()[position]);
            }
            mChart.invalidate();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    };

    public void onMenuClicked() {
        showMenu();
    }

    private LineDataSet createSet(String label, int color) {
        LineDataSet set = new LineDataSet(null, label);
        set.setAxisDependency(YAxis.AxisDependency.LEFT);
        set.setColor(color);
        set.setCircleColor(color);
        set.setLineWidth(2f);
        set.setCircleRadius(4f);
        //set.setFillAlpha(65);
        //set.setFillColor(ColorTemplate.getHoloBlue());
        set.setHighLightColor(color);
        set.setValueTextColor(color);
        set.setValueTextSize(9f);
        set.setDrawValues(false);
        set.setFormLineWidth(1f);
        set.setValueFormatter(new DefaultValueFormatter(3));
        set.enableDashedHighlightLine(10f, 5f, 0f);
        return set;
    }

    private LineDataSet createRightSet(String label, int color) {
        LineDataSet set = createSet(label, color);
        set.setAxisDependency(YAxis.AxisDependency.RIGHT);
        return set;
    }

    boolean isShowMenu = true;
    float menuY = 0, menuHeight = 0, menuBtnHeight = 0;
    ObjectAnimator menuAnim;

    private void showMenu() {
        if (menuAnim == null) {
            menuAnim = new ObjectAnimator();
            menuAnim.setInterpolator(new AccelerateDecelerateInterpolator());
            menuAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    menuBtn.setY((Float) animation.getAnimatedValue() - menuBtnHeight);
                }
            });
        }
        if (menuY == 0) {
            menuY = menuLayout.getY();
            menuHeight = menuLayout.getHeight();
            menuBtnHeight = menuBtn.getHeight();
        }
        if (menuAnim.isRunning())
            menuAnim.cancel();

        if (isShowMenu) {
            if (menuLayout.getY() < menuY + menuHeight)//隐藏菜单
            {
                menuAnim.setTarget(menuLayout);
                menuAnim.setPropertyName("Y");
                menuAnim.setFloatValues(menuLayout.getY(), menuY + menuHeight);
                menuAnim.setDuration(500);
                menuAnim.start();
            }

        } else {
            if (menuLayout.getY() > menuY)//显示菜单
            {
                menuAnim.setTarget(menuLayout);
                menuAnim.setPropertyName("Y");
                menuAnim.setFloatValues(menuLayout.getY(), menuY);
                menuAnim.setDuration(500);
                menuAnim.start();
            }
        }
        isShowMenu = !isShowMenu;
    }


    @Override
    public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {

    }

    @Override
    public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {

    }

    @Override
    public void onChartLongPressed(MotionEvent me) {

    }

    @Override
    public void onChartDoubleTapped(MotionEvent me) {

    }

    @Override
    public void onChartSingleTapped(MotionEvent me) {

    }

    @Override
    public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {

    }

    @Override
    public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
        RectF rectF = mChart.getContentRect();
        double temp;
        MPPointD pointD = mChart.getValuesByTouchPoint(rectF.left, rectF.top, YAxis.AxisDependency.LEFT);
        //Log.i("trans", "" + pointD.y);
        temp = pointD.y;
        pointD = mChart.getValuesByTouchPoint(rectF.left, rectF.bottom, YAxis.AxisDependency.LEFT);
        //Log.i("trans", "" + pointD.y);
        contentCenterY = (float) ((temp + pointD.y) / 2);
    }

    @Override
    public void onChartTranslate(MotionEvent me, float dX, float dY) {
        RectF rectF = mChart.getContentRect();
        double temp;
        MPPointD pointD = mChart.getValuesByTouchPoint(rectF.left, rectF.top, YAxis.AxisDependency.LEFT);
        //Log.i("trans", "" + pointD.y);
        temp = pointD.y;
        pointD = mChart.getValuesByTouchPoint(rectF.left, rectF.bottom, YAxis.AxisDependency.LEFT);
        //Log.i("trans", "" + pointD.y);
        contentCenterY = (float) ((temp + pointD.y) / 2);
    }

    @Override
    public void onValueSelected(Entry e, Highlight h) {

    }

    @Override
    public void onNothingSelected() {

    }

    public void onDestory() {
        if (chartThread != null && chartThread.isAlive()) {
            chartThread.interrupt();
            chartThread = null;
        }
    }

    private Thread chartThread;

    private void startChartThread() {
        if (chartThread == null || !chartThread.isAlive()) {
            chartThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(190);
                            //semaphore.acquire();
                            isUIRun = true;
                            activity.runOnUiThread(UIRunnable);
                            while (isUIRun) {
                                Thread.sleep(10);
                            }
                            if (uiThreadRun != null)
                                uiThreadRun.run();
                        } catch (InterruptedException e) {
                            Log.i("UI", "ChartThread Stopped!");
                            break;
                        }
                    }
                }
            });
            chartThread.setPriority(Thread.MIN_PRIORITY);
            chartThread.setName("UI 更新线程");
        }
        if (!chartThread.isAlive())
            chartThread.start();
    }

    private void stopChartThread() {
        if (chartThread != null && chartThread.isAlive()) {
            chartThread.interrupt();
        }
    }

    public void setUiThreadListener(Runnable uiThreadRun) {
        this.uiThreadRun = uiThreadRun;
    }
}
